package com.timsmeet.timeperiod;

import java.util.Calendar;

import com.timsmeet.utils.ArgumentValidator;

public class TimePeriodCalc {
	
	public static boolean hasInside(TimePeriod period, Calendar test) {
		return 
		TimePeriodUtils.compareTrimedCalendar(test, period.getStart()) >= 0
		&&
		TimePeriodUtils.compareTrimedCalendar(test, period.getEnd()) <= 0;
	}

	public static boolean hasInside(TimePeriod period, TimePeriod test) {
		return hasInside(period, test.getStart()) && hasInside(period, test.getEnd());
	}
	
	public static boolean intersectsWith(TimePeriod period, TimePeriod test) {
		return
			hasInside(period, test.getStart()) ||
			hasInside(period, test.getEnd()) ||
			(
					TimePeriodUtils.compareTrimedCalendar(test.getStart(), period.getStart()) < 0
					&&
					TimePeriodUtils.compareTrimedCalendar(test.getEnd(), period.getEnd()) > 0
			);
	}

	// ----------------------------------------------------------------------
	public static boolean overlapsWith(TimePeriod period, TimePeriod test) {
		PeriodRelation relation = getRelation( period, test );
		return
			relation != PeriodRelation.AFTER &&
			relation != PeriodRelation.START_TOUCHING &&
			relation != PeriodRelation.END_TOUCHING &&
			relation != PeriodRelation.BEFORE;
	}
	
	public static PeriodRelation getRelation(TimePeriod period, TimePeriod test) {
		ArgumentValidator.isNotNull(period, "period");
		ArgumentValidator.isNotNull(test, "test");
		
		if(TimePeriodUtils.compareTrimedCalendar(test.getEnd(), period.getStart()) < 0) {
			return PeriodRelation.AFTER;
		}
		if(TimePeriodUtils.compareTrimedCalendar(test.getStart(), period.getEnd()) > 0) {
			return PeriodRelation.BEFORE;
		}
		if(TimePeriodUtils.compareTrimedCalendar(test.getStart(), period.getStart()) == 0
				&& TimePeriodUtils.compareTrimedCalendar(test.getEnd(), period.getEnd()) ==0) {
			return PeriodRelation.EXACT_MATCH;
		}
		if(TimePeriodUtils.compareTrimedCalendar(test.getEnd(), period.getStart()) == 0) {
			return PeriodRelation.START_TOUCHING;
		}
		if(TimePeriodUtils.compareTrimedCalendar(test.getStart(), period.getEnd()) == 0) {
			return PeriodRelation.END_TOUCHING;
		}
		if(hasInside(period, test)) {
			if(TimePeriodUtils.compareTrimedCalendar(test.getStart(), period.getStart()) == 0) {
				return PeriodRelation.ENCLOSING_START_TOUCHING;
			} else if(TimePeriodUtils.compareTrimedCalendar(test.getEnd(), period.getEnd()) == 0) {
				return PeriodRelation.ENCLOSING_END_TOUCHING;
			} else {
				return PeriodRelation.ENCLOSING;
			}
		}
		boolean periodContainsMyStart = hasInside(test, period.getStart());
		boolean periodContainsMyEnd = hasInside(test, period.getEnd());
		if(periodContainsMyStart && periodContainsMyEnd) {
			if(TimePeriodUtils.compareTrimedCalendar(test.getStart(), period.getStart()) == 0) {
				return PeriodRelation.INSIDE_START_TOUCHING;
			} else if(TimePeriodUtils.compareTrimedCalendar(test.getEnd(), period.getEnd()) == 0) {
				return PeriodRelation.INSIDE_END_TOUCHING;
			} else {
				return PeriodRelation.INSIDE;
			}
		}
		if(periodContainsMyStart) {
			return PeriodRelation.START_INSIDE;
		}
		if(periodContainsMyEnd) {
			return PeriodRelation.END_INSIDE;
		}
		throw new IllegalStateException("invalid period relation of '" + period + "' and '" + test + "'");
	}
}
